#include "FSMBase.h"

NS_GNS_BEGIN

FSMRef::FSMRef()
:_curEvent(nullptr)
, _curState(nullptr)
, _startState(nullptr)
{
	
}

FSMRef::~FSMRef()
{
	clear();
}


void FSMRef::clear()
{
	map<string, FSMState*>::iterator stateit;
	for (stateit = _states.begin(); stateit != _states.end(); stateit++)
	{
		delete stateit->second;
	}

	map<string, FSMEvent*>::iterator eventit;
	for (eventit = _events.begin(); eventit != _events.end(); eventit++)
	{
		delete eventit->second;
	}
}

void gns::FSMRef::addState(FSMState* state)
{
	_states[state->getName()] = state;
}

void gns::FSMRef::addEvent(FSMEvent* event)
{
	_events[event->getName()] = event;
}

//void FSMRef::addState(string name)
//{
//	FSMState* state = new FSMState(name);
//	_states[name] = state;
//}
//void FSMRef::addState(string name, callback enter, callback leave)
//{
//	FSMState* state = new FSMState(name, enter, leave);
//	_states[name] = state;
//}
//void FSMRef::addEvent(string name, string from, string to)
//{
//	FSMEvent* event = new FSMEvent(name, from, to);
//	_events[name] = event;
//}
//void FSMRef::addEvent(string name, string from, string to, callback enter, callback leave)
//{
//	FSMEvent* event = new FSMEvent(name, from, to, enter, leave);
//	_events[name] = event;
//}
bool FSMRef::doEvent(string name)
{
	bool re = false;
	auto it = _events.find(name);
	if (it == _events.end())
		return re;

	FSMEvent* event = it->second;
	re = doEvent(event);

	return re;
}
bool FSMRef::doEvent(FSMEvent* event)
{
	bool re = false;

	//from
	int len = event->_from.size();
	FSMState* from = nullptr;
	for (int i = 0; i < len; i++)
	{
		if (event->_from[i]->getName() == _curState->getName())
		{
			from = event->_from[i];
			break;
		}
	}
	if (!from)
		return re;

	//to
	auto itto = _states.find(event->_to->getName());
	if (itto == _states.end())
		return re;

	FSMState* to = itto->second;

	//change state
	if (_curEvent && _curEvent->onLeave)
		_curEvent->onLeave();

	_curEvent = event;

	if (_curState->onLeave)
		_curState->onLeave();

	_previousStateName = _curState->getName();
	_curState = to;

	if (_curState->onEnter)
		_curState->onEnter();

	if (_curEvent->onEnter)
		_curEvent->onEnter();

	re = true;
	return re;
}
bool FSMRef::doStart()
{
	return doStart(_startState->getName());
}
bool FSMRef::doStart(string statename)
{
	bool re = false;
	auto it = _states.find(statename);
	if (it != _states.end() && _curState == nullptr)
	{
		re = true;
		_curState = it->second;
		_curState->onEnter();
	}
	return re;
}

bool gns::FSMRef::doStop()
{
	if (_curEvent && _curEvent->onLeave)
		_curEvent->onLeave();

	_curEvent = nullptr;

	if (_curState->onLeave)
		_curState->onLeave();

	_curState = nullptr;

	clear();

	return true;
}

FSMBase::FSMBase()
{
}

FSMBase::~FSMBase()
{
}

void FSMBase::init()
{
	_currentAction = nullptr;
	_actions = new stack<FSMActionBase*>();
}

void FSMBase::update(float dt)
{
	if (_currentAction != nullptr)
	{
		_currentAction->update(dt);
	}
	else if (!_actions->empty())
	{
		_currentAction = _actions->top();
		_actions->pop();
		_currentAction->update(dt);
	}
	else
	{
		onEmpty();
	}
}

NS_GNS_END